#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>

//任务队列
template <class T>
class BlockQueue
{
    static const int defalutnum = 20; //队列大小

public:
    //构造
    BlockQueue(int maxcap = defalutnum)
    : _maxcap(maxcap)
    {
        //锁和条件变量初始化
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_ccond, nullptr);
        pthread_cond_init(&_pcond, nullptr);
    }

    //出任务
    T pop()
    {
        pthread_mutex_lock(&_mutex);

        //判断也是共享资源要加锁，没任务就进入消费者条件等待队列，while防止伪唤醒
        while(_q.size() == 0) 
        {
            pthread_cond_wait(&_ccond, &_mutex); 
        }
        //出任务
        T out = _q.front(); 
        _q.pop();
        //唤醒生产者条件等待队列
        pthread_cond_signal(&_pcond); 

        pthread_mutex_unlock(&_mutex);
        return out;
    }

    //放任务
    void push(const T& in)
    {
        pthread_mutex_lock(&_mutex);

        //任务满了就进入生产者条件等待队列
        while(_q.size() == _maxcap)
        { 
            pthread_cond_wait(&_pcond, &_mutex); 
        }
        //放任务 
        _q.push(in);    
        //唤醒消费者等待队列                
        pthread_cond_signal(&_ccond);

        pthread_mutex_unlock(&_mutex);
    }

    //析构
    ~BlockQueue()
    {
        //锁和条件变量的销毁
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_ccond);
        pthread_cond_destroy(&_pcond);
    }
    
private:
    std::queue<T> _q; //任务队列
    int _maxcap; //任务队列最大值
    pthread_mutex_t _mutex; //生产消费共用锁
    pthread_cond_t _ccond; //消费者条件等待队列
    pthread_cond_t _pcond; //生产者条件等待队列
};